package com.imis.base.aspect;

import com.imis.base.annotation.HashCache;
import com.imis.base.annotation.HashCacheEvict;
import com.imis.base.util.ConvertUtils;
import com.imis.base.util.RedisUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * <p>
 * HashCacheAspect<br>
 * 以HASH形式存储的缓存注解 切面处理类
 * </p>
 *
 * @author XinLau
 * @version 1.0
 * @since 2020年03月24日 14:37
 */
@Aspect
@Component
public class HashCacheAspect extends BaseAspect {

    /**
     * Redis 工具类
     */
    @Resource
    private RedisUtil redisUtil;

    /**
     * 缓存逻辑
     *
     * @param proceedingJoinPoint - ProceedingJoinPoint
     * @return Object - 返回值
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/24 15:35
     */
    @Around("@annotation(com.imis.base.annotation.HashCache)")
    public Object hashCache(ProceedingJoinPoint proceedingJoinPoint) {
        // 1.获取被拦截方法对象
        Method method = getMethod(proceedingJoinPoint);
        // 2.获取 Annotation
        HashCache hashCache = method.getAnnotation(HashCache.class);
        // 3.获取HASH的HASH标识
        String hashIdentification = hashCache.hashIdentification();
        // 存放的Key
        String hashKey = generateStringBySpEL(hashCache.hashKey(), proceedingJoinPoint);
        // 过期时间
        int expireTime = hashCache.expireTime();
        // 4.获取方法的返回类型,让缓存可以返回正确的类型
        Class returnType = ((MethodSignature) proceedingJoinPoint.getSignature()).getReturnType();
        // 5.使用 Redis 的 HASH 进行存取，易于管理
        Object result = redisUtil.hget(hashIdentification, hashKey, returnType);
        if (ConvertUtils.isEmpty(result)) {
            // 缓存为空
            try {
                //  6.获取使用注解的方法的返回值
                result = proceedingJoinPoint.proceed();
                Assert.notNull(hashKey, "HASH内存放的Key");
                //  7.缓存存放
                if (expireTime >= 0) {
                    //  带过期时间（包括0 - 立即过期）
                    redisUtil.hset(hashIdentification, hashKey, result, expireTime);
                } else {
                    //  不带过期时间
                    redisUtil.hset(hashIdentification, hashKey, result);
                }
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        }
        return result;
    }

    /**
     * 缓存清除
     *
     * @param joinPoint - JoinPoint
     * @return Object - 返回值
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/25 09:35
     */
    @Before("@annotation(com.imis.base.annotation.HashCacheEvict)")
    public void hashCacheEvict(JoinPoint joinPoint) {
        // 1.获取被拦截方法对象
        Method method = getMethod(joinPoint);
        // 2.获取 Annotation
        HashCacheEvict hashCacheEvict = method.getAnnotation(HashCacheEvict.class);
        // 3.获取HASH的HASH标识
        String hashIdentification = hashCacheEvict.hashIdentification();
        // Key
        String hashKey = generateStringBySpEL(hashCacheEvict.hashKey(), joinPoint);
        // 4.使用 Redis 的 HASH 进行存取，易于管理
        if (ConvertUtils.isEmpty(hashKey)) {
            Map<Object, Object> result = redisUtil.hmget(hashIdentification);
            if (!result.isEmpty()) {
                redisUtil.del(hashIdentification);
            }
        } else {
            Object result = redisUtil.hget(hashIdentification, hashKey);
            if (ConvertUtils.isNotEmpty(result)) {
                redisUtil.del(hashIdentification, hashKey);
            }
        }
    }

    /**
     * 缓存修改
     *
     * @param proceedingJoinPoint - ProceedingJoinPoint
     * @return Object - 返回值
     * @author XinLau
     * @creed The only constant is change ! ! !
     * @since 2020/3/24 15:35
     */
    @Around("@annotation(com.imis.base.annotation.HashCachePut)")
    public Object hashCachePut(ProceedingJoinPoint proceedingJoinPoint) {
        // 1.获取被拦截方法对象
        Method method = getMethod(proceedingJoinPoint);
        // 2.获取 Annotation
        HashCache hashCache = method.getAnnotation(HashCache.class);
        // 3.获取HASH的HASH标识
        String hashIdentification = hashCache.hashIdentification();
        // 存放的Key
        String hashKey = generateStringBySpEL(hashCache.hashKey(), proceedingJoinPoint);
        // 过期时间
        int expireTime = hashCache.expireTime();
        Object result = null;
        try {
            // 4.获取使用注解的方法的返回值
            result = proceedingJoinPoint.proceed();
            Assert.notNull(hashKey, "HASH内存放的Key");
            // 5.缓存存放
            if (expireTime >= 0) {
                //  带过期时间（包括0 - 立即过期）
                redisUtil.hset(hashIdentification, hashKey, result, expireTime);
            } else {
                //  不带过期时间
                redisUtil.hset(hashIdentification, hashKey, result);
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return result;
    }

}
